package com.wichell.framework.util;

import java.io.IOException;
import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.springframework.util.ReflectionUtils;

import com.wichell.framework.exception.HttpRequestException;

import okhttp3.Authenticator;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.OkHttpClient.Builder;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.BufferedSink;

public class HttpRequestUtil {

	private static Builder okHttpClientBuilder = new OkHttpClient().newBuilder();

	public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

	private static int TIMEOUT = 30;

	private static final Logger LOGGER = Logger.getLogger(HttpRequestUtil.class);

	public static String doFormPost(String url, Object obj) throws HttpRequestException {
		return doFormPost(url, obj, TIMEOUT);
	}

	public static String doFormPost(String url, Object obj, int timeout) throws HttpRequestException {
		FormRequestBody requestBody = new FormRequestBody(buildPostRequestParam(obj));
		Request request = new Request.Builder().post(requestBody).url(url).build();
		return request(url, requestBody.toString(), timeout, request);
	}

	/**
	 * POST拼接参数
	 *
	 * @return
	 */
	private static FormBody buildPostRequestParam(Object obj) {
		FormBody.Builder builder = new FormBody.Builder();
		Field[] fields = obj.getClass().getDeclaredFields();
		for (Field f : fields) {
			ReflectionUtils.makeAccessible(f);
			Object result = ReflectionUtils.getField(f, obj);
			if (result != null) {
				builder.add(f.getName(), String.valueOf(result));
			}
		}
		return builder.build();
	}

	public static void createHttpClientByAuth(Authenticator authenticator) {
		if (null != authenticator) {
			okHttpClientBuilder.authenticator(authenticator);
		}
	}

	public static String doJson(String url, String param) throws HttpRequestException {
		return doJson(url, param, TIMEOUT);
	}

	public static String doJson(String url, String param, Integer timeout) throws HttpRequestException {
		RequestBody body = RequestBody.create(JSON, param);
		Request request = new Request.Builder().url(url).post(body).build();
		return request(url, param, timeout, request);
	}

	/**   
	 * @Title: doGet   
	 * @Description: Get请求
	 * @param: @param url
	 * @param: @return
	 * @param: @throws HttpRequestException      
	 * @return: String      
	 * @throws   
	 */
	public static String doGet(String url) throws HttpRequestException {
		Request request = new Request.Builder().url(url).build();
		return request(url, "", TIMEOUT, request);
	}

	private static String request(String url, String params, long timeout, Request request)
			throws HttpRequestException {
		OkHttpClient okHttpClient = okHttpClientBuilder.readTimeout(timeout, TimeUnit.SECONDS).build();
		try {
			Response response = okHttpClient.newCall(request).execute();
			if (response.isSuccessful()) {
				String message = response.body().string();
				if (LOGGER.isDebugEnabled()) {
					LOGGER.debug(MessageFormat.format("HTTP请求成功：Url:[{0}],Params:[{1}],Response:[{2}]", url, params,
							response.message()));
				}
				return message;
			} else {
				String errorMessage = MessageFormat.format("HTTP请求失败：Url:[{0}],Params:[{1}],RequestException:[{2}]",
						url, params, response.message());
				LOGGER.error(errorMessage);
				throw new HttpRequestException(errorMessage);
			}
		} catch (IOException e) {
			e.printStackTrace();
			String errorMessage = MessageFormat.format("HTTP请求异常：Url:[{0}],Params:[{1}],IOException:[{2}]", url, params,
					e.getMessage());
			LOGGER.error(errorMessage);
			throw new HttpRequestException(errorMessage);
		}
	}

}

class FormRequestBody extends RequestBody {
	private FormBody requestBody;

	public FormRequestBody(FormBody requestBody) {
		this.requestBody = requestBody;
	}

	@Override
	public MediaType contentType() {
		return requestBody.contentType();
	}

	@Override
	public void writeTo(BufferedSink sink) throws IOException {
		requestBody.writeTo(sink);
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		int size = requestBody.size();
		for (int i = 0; i < size; i++) {
			sb.append(MessageFormat.format("{0}={1}", requestBody.encodedName(i), requestBody.encodedValue(i)));
			sb.append(i < size - 1 ? "&" : "");
		}
		return sb.toString();
	}

}